import datetime
from typing import List, Tuple, Dict

import numpy as np
import pandas as pd
import talib as ta


# 聚宽平台 python 3.6，不支持 dataclass
def __process_date(d):
    """
    将时间统一处理
    :param d:
    :return:
    """
    d = str(d)
    d = d.replace('+08:00', '')
    if len(d) == 10:
        return datetime.datetime.strptime(d, '%Y-%m-%d')
    else:
        return datetime.datetime.strptime(d, '%Y-%m-%d %H:%M:%S')

class Kline:
    def __init__(self, index: int, date: datetime, h: float, l: float, o: float, c: float, a: float):
        self.index: int = index
        self.date: datetime = date
        self.h: float = h
        self.l: float = l
        self.o: float = o
        self.c: float = c
        self.a: float = a


class CLKline:
    def __init__(self, k_index: int, date: datetime, h: float, l: float, o: float, c: float, a: float,
                 index: int = 0, _n: int = 0, _q: bool = False):
        self.k_index: int = k_index
        self.date: datetime = date
        self.h: float = h
        self.l: float = l
        self.o: float = o
        self.c: float = c
        self.a: float = a
        self.index: int = index
        self._n: int = _n  # 记录包含的K线数量
        self._q: bool = _q  # 是否有缺口


class FX:
    def __init__(self, _type: str, k: CLKline, klines: List[CLKline], val: float,
                 index: int = 0, tk: bool = False, real: bool = True, done: bool = True):
        self.type: str = _type
        self.k: CLKline = k
        self.klines: List[CLKline] = klines
        self.val: float = val
        self.index: int = index
        self.tk: bool = tk  # 记录是否跳空
        self.real: bool = real
        self.done: bool = done


class BI:
    def __init__(self, start: FX, end: FX = None, high: float = None, low: float = None, _type: str = None,
                 ld: dict = None, done: bool = None, mmds: list = [], index: int = 0, qs_beichi: bool = False,
                 pz_beichi: bool = False, td: bool = False, fx_num: int = 0):
        self.start: FX = start
        self.end: FX = end
        self.high: float = high
        self.low: float = low
        self.type: str = _type
        self.ld: dict = ld
        self.done: bool = done  # 笔是否完成
        self.mmds: list = mmds  # 买卖点
        self.index: int = index
        self.qs_beichi: bool = qs_beichi  # 趋势背驰
        self.pz_beichi: bool = pz_beichi  # 盘整背驰
        self.td: bool = td  # 笔是否停顿
        self.fx_num: int = fx_num  # 包含的分型数量


class XD:
    def __init__(self, start: FX, end: FX = None, _type: str = None, high: float = None, low: float = None,
                 index: int = 0):
        self.start: FX = start
        self.end: FX = end
        self.type: str = _type
        self.high: float = high
        self.low: float = low
        self.index: int = index


class ZS:
    def __init__(self, start: FX, bis: List[BI], end: FX = None, zg: float = None, zd: float = None,
                 gg: float = None, dd: float = None, _type: str = None, index: int = 0, bi_num: int = 0,
                 level: int = 0, is_high_kz: bool = False, max_ld: dict = None):
        self.start: FX = start
        self.bis: List[BI] = bis
        self.end: FX = end
        self.zg: float = zg
        self.zd: float = zd
        self.gg: float = gg
        self.dd: float = dd
        self.type: str = _type
        self.index: int = index
        self.bi_num: int = bi_num
        self.level: int = level  # 中枢级别 0 本级别 1 上一级别 ...
        self.is_high_kz: bool = is_high_kz  # 中枢是否是高级别的扩展
        self.max_ld: dict = max_ld  # 记录中枢中最大笔力度


class CL:
    """
    缠论类
    """

    def __init__(self, code: str, klines: pd.DataFrame, frequency: str):
        """
        缠论计算
        :param klines:
        :param frequency:
        """
        self.code = code
        self.frequency = frequency

        # 计算后保存的值
        self.klines, self.cl_klines = self.process_cl_kline(klines)
        self.idx = self.process_idx()  # 计算技术指标
        self.fxs = self.process_fx()
        self.bis = self.process_bi()
        # self.process_ld()  # 处理笔的力度
        # self.xds = self.process_xd()
        # self.zss = self.process_zs(self.bis)
        # self.process_mmds()
    def process_cl_kline(self, klines: pd.DataFrame) -> Tuple[List[Kline], List[CLKline]]:
        """
        将初始 K 线整理为缠论包含关系的 k 线
        :return:
        """
        new_klines = []
        cl_klines = []
        #print(klines)
        for i in range(len(klines)):
            nk = klines.iloc[i]
#             print(nk)
            date = self.__process_date(nk['date'])
            # print(date)
            _k = Kline(index=i, date=date,
                       h=float(nk['high']), l=float(nk['low']),
                       o=float(nk['open']), c=float(nk['close']), a=float(nk['volume']))
            new_klines.append(_k)

            _cl_k = CLKline(date=date, k_index=i,
                            h=float(nk['high']), l=float(nk['low']),
                            o=float(nk['open']), c=float(nk['close']), a=float(nk['volume']),
                            _n=1, _q=False)
#             print(_cl_k.__dict__)
            # 判断是否有跳空缺口
            if len(new_klines) > 2 and (new_klines[-1].l >= new_klines[-2].h or new_klines[-1].h <= new_klines[-2].l):
                _cl_k._q = True
                #print("跳空缺口",_cl_k.__dict__)

            if i <= 1:
                # 前两根 K线 直接插入
                cl_klines.append(_cl_k)
                #print("前两根 K线 直接插入",cl_klines[-1].__dict__)
                continue
            upup_k = cl_klines[-2]
            up_k = cl_klines[-1]
            # 判断趋势
            qushi = 'up' if up_k.h > upup_k.h else 'down'

            if (up_k.h >= _cl_k.h and up_k.l <= _cl_k.l) \
                    or (_cl_k.h >= up_k.h and _cl_k.l <= up_k.l):
                if qushi == 'up':  # 趋势上涨，向上合并
                    up_k.k_index = up_k.k_index if up_k.h > _cl_k.h else _cl_k.k_index
                    up_k.date = up_k.date if up_k.h > _cl_k.h else _cl_k.date
                    up_k.h = max(up_k.h, _cl_k.h)
                    up_k.l = max(up_k.l, _cl_k.l)
                    up_k.a += _cl_k.a  # 交易量累加
                    #print("判断趋势",up_k.date,_cl_k.__dict__,)
                else:
                    up_k.k_index = up_k.k_index if up_k.l < _cl_k.l else _cl_k.k_index
                    up_k.date = up_k.date if up_k.l < _cl_k.l else _cl_k.date
                    up_k.h = min(up_k.h, _cl_k.h)
                    up_k.l = min(up_k.l, _cl_k.l)
                    up_k.a += _cl_k.a
                up_k._n += 1
                continue

            cl_klines.append(_cl_k)


        # 规整缠论的 K 线数据
        up_k = cl_klines[0]
        for i in range(len(cl_klines)):
            cl_klines[i].index = i  # 重新编号
            if cl_klines[i].h > up_k.h:
                cl_klines[i].o = cl_klines[i].l
                cl_klines[i].c = cl_klines[i].h
            else:
                cl_klines[i].o = cl_klines[i].h
                cl_klines[i].c = cl_klines[i].l
            up_k = cl_klines[i]

        #print(new_klines[-1].__dict__,cl_klines[-1].__dict__)

        return new_klines, cl_klines
    def process_idx(self) -> map:
        """
        计算所需要的技术指标
        :return:
        """
        prices = []
        for k in self.klines:
            #print(k.__dict__)
            prices.append(k.c)
        # 计算 macd
        macd_dif, macd_dea, macd_hist = ta.MACD(np.array(prices), fastperiod=12, slowperiod=26, signalperiod=9)
        macd = {'dea': macd_dea, 'dif': macd_dif, 'hist': macd_hist}

        # 计算 BOLL 指标
        boll_up, boll_mid, boll_low = ta.BBANDS(np.array(prices), timeperiod=13)
        # print(macd,)
        # print(boll_up, boll_mid, boll_low)
        return {
            'macd': macd,
            'boll': {'up': boll_up, 'mid': boll_mid, 'low': boll_low}
        }
    def process_fx(self) -> List[FX]:
        """
        找出图形中的 分型
        :return:
        """
        fxs = []
        #print("///////////",self.cl_klines[-1].__dict__)
        for i in range(1, len(self.cl_klines) - 1):
            up_k = self.cl_klines[i - 1]
            now_k = self.cl_klines[i]
            next_k = self.cl_klines[i + 1]
            fx = None
            if (up_k.h < now_k.h and now_k.h > next_k.h) \
                    and (up_k.l < now_k.l and now_k.l > next_k.l):
                tiaokong = True if (up_k.h < now_k.l or now_k.l > next_k.h) else False
                fx = FX(_type='ding', k=now_k, klines=[up_k, now_k, next_k], val=now_k.h, tk=tiaokong,
                        real=True, done=True)
            if (up_k.h > now_k.h and now_k.h < next_k.h) \
                    and (up_k.l > now_k.l and now_k.l < next_k.l):
                tiaokong = True if (up_k.l > now_k.h or now_k.h < next_k.l) else False
                fx = FX(_type='di', k=now_k, klines=[up_k, now_k, next_k], val=now_k.l, tk=tiaokong,
                        real=True, done=True)
            #print("1111111",fx,i,now_k.date)
            if fx is not None:
                if len(fxs) == 0:
                    fxs.append(fx)
                    continue

                up_fx = self.__get_up_real_fx(fxs)
                #print("分形",up_fx.type,up_fx.k.__dict__,len(up_fx.klines),up_fx.klines[-3].__dict__,up_fx.klines[-2].__dict__,up_fx.klines[-1].__dict__)
                if up_fx is False:
                    continue

                if fx.type == 'ding' and up_fx.type == 'ding' and up_fx.k.h <= fx.k.h:
                    # 连续两个顶分型，前面的低于后面的，只保留后面的，前面的去掉
                    up_fx.real = False
                    fxs.append(fx)
                elif fx.type == 'di' and up_fx.type == 'di' and up_fx.k.l >= fx.k.l:
                    # 连续两个底分型，前面的高于后面的，只保留后面的，前面的去掉
                    up_fx.real = False
                    fxs.append(fx)
                elif fx.type == up_fx.type:
                    # 相邻的性质，必然前顶不能低于后顶，前底不能高于后底，遇到相同的，只保留第一个
                    fx.real = False
                    fxs.append(fx)
                elif fx.type == 'ding' and up_fx.type == 'di' \
                        and (fx.k.h <= up_fx.k.l or fx.k.l <= up_fx.k.h):
                    # 当前分型 顶，上一个分型 底，当 顶 低于 底，是个无效的顶，跳过
                    fx.real = False
                    fxs.append(fx)
                elif fx.type == 'di' and up_fx.type == 'ding' \
                        and (fx.k.l >= up_fx.k.h or fx.k.h >= up_fx.k.l):
                    # 当前分型 底，上一个分型 顶 ，当 底 高于 顶，是个无效顶底，跳过
                    fx.real = False
                    fxs.append(fx)
                else:
                    # 顶与底直接底非包含关系的 K线 数量大于等于3
                    if fx.k.index - up_fx.k.index >= 4:
                        fxs.append(fx)
                    else:
                        fx.real = False
                        fxs.append(fx)

        # 计算最后一段未完成的笔，如果符合随时可完成的状态，记录分型
        up_fx = self.__get_up_real_fx(fxs)
        #print(";;;;;;;;;",up_fx.type,up_fx.k.__dict__)
        if up_fx:
            end_k = self.cl_klines[-1]
            # 顶分型 突破新高，将笔画到新高点
            if up_fx.type == 'ding' and end_k.h > up_fx.k.h:
                up_fx.real = False
                fxs.append(
                    FX(_type='ding', k=end_k, klines=[self.cl_klines[-2], end_k, None], val=end_k.h, tk=False,
                       real=True, done=False)
                )
            elif up_fx.type == 'ding' and end_k.index - up_fx.k.index >= 4 \
                    and end_k.l < up_fx.k.l and end_k.h < up_fx.k.h \
                    and up_fx.k.index != fxs[-1].k.index:
                fxs.append(
                    FX(_type='di', k=end_k, klines=[self.cl_klines[-2], end_k, None], val=end_k.l, tk=False,
                       real=True, done=False)
                )
            # 底分型 突破新低，将笔画到新低点
            elif up_fx.type == 'di' and end_k.l < up_fx.k.l:
                up_fx.real = False
                fxs.append(
                    FX(_type='di', k=end_k, klines=[self.cl_klines[-2], end_k, None], val=end_k.l, tk=False,
                       real=True, done=False)
                )
            elif up_fx.type == 'di' and end_k.index - up_fx.k.index >= 4 \
                    and end_k.h > up_fx.k.h and end_k.l > up_fx.k.l \
                    and up_fx.k.index != fxs[-1].k.index:
                fxs.append(
                    FX(_type='ding', k=end_k, klines=[self.cl_klines[-2], end_k, None], val=end_k.h, tk=False,
                       real=True, done=False)
                )

        # 给分型编号，后续好直接查找
        for i in range(len(fxs)):
            fxs[i].index = i
        # print(fxs[-1].__dict__,fxs[-1].klines[-1].__dict__)
        return fxs,up_fx
    def process_bi(self) -> List[BI]:
        """
        找出顶分型与低分型连接的 笔
        :return:
        """
        bis = []
        bi = None
        # 记录一笔中，无效的顶底分型数量
        _dd_total = 0
        for fx in self.fxs[0]:
            if not fx.real:
                _dd_total += 1
                continue

            if bi is None:
                bi = BI(start=fx)
                continue

            if bi.start.type == fx.type:
                # 相同分型跳过
                continue
            #print("fx",fx.__dict__,fx.k.__dict__)
            #print("fx", fx.type, fx.k.__dict__)
            bi.end = fx
            bi.type = 'up' if bi.start.type == 'di' else 'down'
            bi.high = max(bi.start.val, bi.end.val)
            bi.low = min(bi.start.val, bi.end.val)
            bi.qs_beichi = False
            bi.pz_beichi = False
            bi.mmds = []
            bi.done = fx.done
            bi.td = False
            bi.fx_num = _dd_total
            bis.append(bi)
            # 重置技术
            bi = BI(start=fx)
            _dd_total = 0
            #print("bi",bi.__dict__,bi.start.__dict__,bi.start.k.__dict__)

        # 确认最后笔分型是否停顿(只计算最后指定几笔的，之前的没必要算了)
        if len(bis) > 0:
            loop_num = min(6, len(bis) - 1)
            for i in range(1, loop_num):
                last_bi = bis[-i]
                if last_bi.done and len(self.cl_klines) > last_bi.end.k.index + 1:
                    cl_kline_next = self.cl_klines[last_bi.end.k.index + 1]
                    for i in range(last_bi.end.k.k_index + 1, len(self.klines)):
                        if last_bi.type == 'up' and self.klines[i].c < cl_kline_next.l:
                            last_bi.td = True
                            break
                        if last_bi.type == 'down' and self.klines[i].c > cl_kline_next.h:
                            last_bi.td = True
                            break

        # 给 笔 编号，后续好直接找
        for i in range(0, len(bis)):
            bis[i].index = i

        # 从新计算高低值，包含其中的K线
        for bi in bis:
            for i in range(bi.start.k.k_index, bi.end.k.k_index + 1):
                bi.high = max(bi.high, self.klines[i].h)
                bi.low = min(bi.low, self.klines[i].l)
        #print("bis",bis[-1].__dict__)
#         print("start",bis[-3].start.type,bis[-3].start.k.__dict__)
#         print("end", bis[-3].end.type, bis[-3].end.k.__dict__)
#         print("start",bis[-2].start.type,bis[-2].start.k.__dict__)
#         print("end", bis[-2].end.type, bis[-2].end.k.__dict__)
        #print("start",bis[-1].start.type,bis[-1].start.k.__dict__)
        #print("end", bis[-1].end.type, bis[-1].end.k.__dict__)
        return bis
    def __process_date(self, d):
        """
        将时间统一处理
        :param d:
        :return:
        """
        d = str(d)
        d = d.replace('+08:00', '')
        if len(d) == 10:
            return datetime.datetime.strptime(d, '%Y-%m-%d')
        else:
            return datetime.datetime.strptime(d, '%Y-%m-%d %H:%M:%S')

    def __get_up_real_fx(self, fxs: List[FX]) -> FX:
        """
        查找上一个确认的分型
        :return:
        """
        for i in range(1, len(fxs) + 1):
            f = fxs[-i]
            if f.real:
                return f
        return False

    def __find_bi_xulie_fx(self, fx_type='ding'):
        """
        查找笔序列分型
        :param fx_type:
        :return:
        """
        xulie = []
        for i in range(1, len(self.bis)):
            bi = self.bis[i]
            if (fx_type == 'ding' and bi.type == 'down') or (fx_type == 'di' and bi.type == 'up'):
                now_xl = {'max': bi.high, 'min': bi.low, 'bi': bi}
                if len(xulie) == 0:
                    xulie.append(now_xl)
                    continue
                qs = 'up' if fx_type == 'ding' else 'down'
                up_xl = xulie[-1]
                if (up_xl['max'] >= now_xl['max'] and up_xl['min'] <= now_xl['min']) \
                        or (up_xl['max'] <= now_xl['max'] and up_xl['min'] >= now_xl['min']):
                    del (xulie[-1])
                    if qs == 'up':
                        now_xl['max'] = max(up_xl['max'], now_xl['max'])
                        now_xl['min'] = max(up_xl['min'], now_xl['min'])
                    else:
                        now_xl['max'] = min(up_xl['max'], now_xl['max'])
                        now_xl['min'] = min(up_xl['min'], now_xl['min'])
                    xulie.append(now_xl)
                else:
                    xulie.append(now_xl)

        xl_fxs = []
        for i in range(1, len(xulie) - 1):
            up_xl = xulie[i - 1]
            now_xl = xulie[i]
            next_xl = xulie[i + 1]
            if fx_type == 'ding' and up_xl['max'] <= now_xl['max'] and now_xl['max'] >= next_xl['max']:
                now_xl['type'] = 'ding'
                xl_fxs.append(now_xl)
            if fx_type == 'di' and up_xl['min'] >= now_xl['min'] and now_xl['min'] <= next_xl['min']:
                now_xl['type'] = 'di'
                xl_fxs.append(now_xl)

        return xl_fxs

    def __cross_qujian(self, qj_one, qj_two):
        """
        计算两个范围相交部分区间
        :param qj_one:
        :param qj_two:
        :return:
        """
        # 判断线段是否与范围值内有相交
        max_one = max(qj_one[0], qj_one[1])
        min_one = min(qj_one[0], qj_one[1])
        max_two = max(qj_two[0], qj_two[1])
        min_two = min(qj_two[0], qj_two[1])

        cross_max_val = min(max_two, max_one)
        cross_min_val = max(min_two, min_one)

        if cross_max_val >= cross_min_val:
            return {'max': cross_max_val, 'min': cross_min_val}
        else:
            return None

    def __create_zs(self, bis: List[BI]) -> [ZS, None]:
        """
        创建中枢
        :param bis:
        :return:
        """
        if len(bis) < 3:
            return None
        zs = ZS(start=bis[0].start, bis=[bis[0]])

        zs_fanwei = [bis[0].high, bis[0].low]
        zs_gg = bis[0].high
        zs_dd = bis[0].low
        for i in range(1, len(bis)):
            bi = bis[i]
            bi_fanwei = [bi.high, bi.low]
            cross_fanwei = self.__cross_qujian(zs_fanwei, bi_fanwei)
            if cross_fanwei is None:
                return None
            zs_gg = max(zs_gg, bi.high)
            zs_dd = min(zs_dd, bi.low)
            if i <= 2:
                zs_fanwei = [cross_fanwei['max'], cross_fanwei['min']]
            zs.bis.append(bi)
            # 根据笔数量，计算级别
            zs.bi_num = len(zs.bis)
            zs.level = (zs.bi_num % 3) - 1
            zs.end = bi.end
            # 记录中枢中，最大的笔力度
            if zs.max_ld is None:
                zs.max_ld = bi.ld
            else:
                zs.max_ld = zs.max_ld if self.__compare_ld_beichi(zs.max_ld, bi.ld) else bi.ld

        zs.zg = zs_fanwei[0]
        zs.zd = zs_fanwei[1]
        zs.gg = zs_gg
        zs.dd = zs_dd

        zs_pre_bi = self.bis[bis[0].index - 1]
        zs_next_bi = None if self.bis[-1].index == bis[-1].index else self.bis[bis[-1].index + 1]
        zs_type = 'up' if bis[0].type == 'down' else 'down'

        if zs_next_bi is None:
            zs.type = 'zd'
        elif zs_pre_bi.type == zs_next_bi.type:  # 进去中枢笔同向，中枢才有方向
            if zs_type == 'up' and zs_pre_bi.low < zs.dd and zs_next_bi.high > zs.gg:
                zs.type = 'up'
            elif zs_type == 'down' and zs_pre_bi.high > zs.gg and zs_next_bi.low < zs.dd:
                zs.type = 'down'
            else:
                zs.type = 'zd'
        else:
            zs.type = 'zd'
        return zs

    def __compare_zs_ld(self, zss: List[ZS], bis: List[BI], end_zs: ZS, end_bi_index: int):
        """
        对比中枢前后力度
        :param zss:
        :param bis:
        :param end_zs:
        :param end_bi_index:
        :return:
        """
        if end_bi_index >= len(bis):
            return

        # 对比 趋势/盘整 背驰
        pre_bi = bis[end_zs.bis[0].index - 1]
        end_bi = bis[end_bi_index]
        pre_zs = zss[-1] if len(zss) > 0 else None

        if pre_zs and end_zs.type in ['up', 'down'] \
                and pre_zs.type == end_zs.type \
                and end_zs.bis[0].index - pre_zs.bis[-1].index <= 3:
            # 趋势背驰判断（有前中枢并且同类型的，并且新高新低的，才有趋势背驰）
            if (end_zs.type == 'up' and end_zs.zd > pre_zs.zg) \
                    or (end_zs.type == 'down' and end_zs.zg < pre_zs.zd):
                if end_bi.qs_beichi is False:
                    if self.__zs_call_back_boll(end_zs) and self.__compare_ld_beichi(pre_bi.ld, end_bi.ld):
                        end_bi.qs_beichi = True
        else:
            # 盘整背驰判断
            if end_bi.pz_beichi is False:
                # 中枢内新高或新低，判断力度，出盘整背驰
                if end_bi.high > end_zs.gg or end_bi.low < end_zs.dd:
                    if self.__compare_ld_beichi(pre_bi.ld, end_bi.ld) and self.__compare_ld_beichi(end_zs.max_ld,
                                                                                                   end_bi.ld):
                        end_bi.pz_beichi = True

        return

    def __compare_ld_beichi(self, one_ld: dict, two_ld: dict):
        """
        比较两个力度，后者小于前者，返回 True
        :param one_ld:
        :param two_ld:
        :return:
        """
        if two_ld['macd']['hist']['sum'] < one_ld['macd']['hist']['sum']:
            return True
        else:
            return False

    def __macd_beichi(self, one_qj: List[FX], zs_qj: List[FX], two_qj: List[FX], beichi_type: str = 'qs') -> bool:
        """
        计算 给定的两端的 macd 是否背驰
        :param one_qj:
        :param zs_qj:
        :param two_qj:
        :param beichi_type:
        :return:
        """
        back_zero = False
        if zs_qj is not None:
            back_zero = self.__macd_call_back_zero(zs_qj[0], zs_qj[1])
        one_ld = self.__query_macd_ld(one_qj[0], one_qj[1])
        two_ld = self.__query_macd_ld(two_qj[0], two_qj[1])

        if beichi_type == 'qs':  # 趋势背驰判断
            if back_zero and two_ld['hist']['sum'] < one_ld['hist']['sum']:
                return True

        elif beichi_type == 'pz':  # 盘整背驰判断
            if two_ld['hist']['sum'] < one_ld['hist']['sum']:
                return True
        return False

    def __macd_call_back_zero(self, start_fx: FX, end_fx: FX):
        """
        检查是否有回调 0 轴
        :param start_fx:
        :param end_fx:
        :return:
        """
        # 确认区间是否回抽0轴
        start_index = start_fx.index
        for bi in self.bis:
            if bi.start.index == start_index:
                if (bi.ld['macd']['dea']['min'] <= 3.1415926 and bi.ld['macd']['dea']['max'] >= -3.1415926) \
                        or (bi.ld['macd']['dif']['min'] <= 3.1415926 and bi.ld['macd']['dif']['max'] >= -3.1415926):
                    return True
                start_index = bi.end.index
            if start_index >= end_fx.index:
                break

        return False

    def __zs_call_back_boll(self, zs: ZS):
        """
        中枢是否回拉boll中轨，替换 macd 回拉零轴判断
        :param zs:
        :return:
        """
        zs_qj = [zs.zg, zs.zd]
        zs_k_index = [zs.bis[0].start.k.k_index, zs.bis[-1].end.k.k_index]
        boll_mid = self.idx['boll']['mid'][zs_k_index[0]:zs_k_index[1]]
        boll_qj = [max(boll_mid), min(boll_mid)]
        cross = self.__cross_qujian(zs_qj, boll_qj)
        if cross is not None:
            return True
        return False

    def __query_macd_ld(self, start_fx: FX, end_fx: FX):
        """
        计算指定位置内的 macd 力度
        :param start_fx:
        :param end_fx:
        :return:
        """
        if start_fx.index > end_fx.index:
            raise Exception('计算力度，开始分型不可以大于结束分型')

        dea = self.idx['macd']['dea'][start_fx.k.k_index:end_fx.k.k_index + 1]
        dif = self.idx['macd']['dif'][start_fx.k.k_index:end_fx.k.k_index + 1]
        hist = self.idx['macd']['hist'][start_fx.k.k_index:end_fx.k.k_index + 1]
        if len(hist) == 0:
            hist = np.array([0])
        if len(dea) == 0:
            dea = np.array([0])
        if len(dif) == 0:
            dif = np.array([0])

        hist_abs = abs(hist)
        hist_sum = hist_abs.sum()
        end_dea = dea[-1]
        end_dif = dif[-1]
        end_hist = hist[-1]

        return {
            'dea': {'end': end_dea, 'max': dea.max(), 'min': dea.min()},
            'dif': {'end': end_dif, 'max': dif.max(), 'min': dif.min()},
            'hist': {'sum': hist_sum, 'end': end_hist},
        }

    def __find_bi_zs(self, bi: BI) -> [None, ZS]:
        """
        查询笔所在的中枢，不包括以此笔起始的中枢
        :param bi:
        :return:
        """
        bi_zs = None
        for zs in self.zss:
            if zs.start.index < bi.start.index:
                bi_zs = zs
            else:
                break
        return bi_zs


if __name__ == '__main__':
    import tushare as ts
    import time
    from get_data import Altas_db

    """
    Data columns (total 6 columns):
    date      1000 non-null object
    open      1000 non-null float64
    high      1000 non-null float64
    low       1000 non-null float64
    close     1000 non-null float64
    volume    1000 non-null float64"""

    df = Altas_db._readdf("ts", "2.his数据下载_fast1_long")

    stock_list= list(set(df.code))
    print(stock_list)
    def xixi(stock_list):
        for code in stock_list:
            print(code)
            time.sleep(0.5)
            ts_get_data = ts.get_hist_data('{}'.format(code))[::-1]
            ts_get_data["date"] = ts_get_data.index
            a = ts_get_data[["date", "open", "high", "low", "close", "volume"]]
            if len(a)<30:
                continue
            cls = []
            # cls.append(CL("000533.XSHE", a, '1d'))
            cls.append(CL("{}".format(code), a, '1d'))
            #->print("{}点时间".format(cls[-1].bis[-1].end.type),code,cls[-1].bis[-1].end.k.date,cls[-1].bis[-1].end.k.c,a[-1:].close.values/cls[-1].bis[-1].end.k.c)
        #     c2=cls[-1].bis[-3].end.k.c
        #     if cls[-1].bis[-1].end.type=="di" and c2<c1:
        #         print("di点时间",code,cls[-1].bis[-1].end.k.date,cls[-1].bis[-3].end.k.date,"超过部分",round(c1/c2-1,2)*100)
            #print(cls[-1].bis[-1].end.k.date != __process_date(str(a[-1:].date.values)[2:-2]))日期不等
            # if cls[-1].bis[-1].type=="down" and a[-1:].close.values/cls[-1].bis[-1].end.k.c-1>0.04 and (cls[-1].bis[-1].end.k.date!=__process_date(str(a[-1:].date.values)[2:-2])):
            #     print(code,"end {} and 今日/低点>0.04".format(cls[-1].bis[-1].end.type),"{}点时间".format(cls[-1].bis[-1].end.type),code,cls[-1].bis[-1].end.k.date,cls[-1].bis[-1].end.k.c,a[-1:].close.values/cls[-1].bis[-1].end.k.c)
            if cls[-1].bis[-1].type=="up":
                print(code,"end {} and 今日/低点>0.04".format(cls[-1].bis[-1].end.type),"{}点时间".format(cls[-1].bis[-1].end.type),code,cls[-1].bis[-1].end.k.date,cls[-1].bis[-1].end.k.c,a[-1:].close.values/cls[-1].bis[-1].end.k.c)



    xixi(stock_list)